package Railroad;

import Railroad.Components.Switch;
import Railroad.Communication.CommData;
import Railroad.Communication.CommDriver;
import Railroad.Communication.MessageBuilder;
import Railroad.Communication.MessageParser;
import Railroad.GUI.RiadenieNavestidiel;
import java.util.ArrayList;
import java.util.List;

public class StatusUpdater implements Runnable {
    private final Zoznam zoznam;
    private boolean running = false;
    private Thread thread;
    private final MessageBuilder builder = new MessageBuilder();
    private final MessageParser parser;
    private final TrackList tracks;
    private final CommDriver commDriver;
    List<TrackUpdateListener> listeners = new ArrayList<>();
  
    
    public StatusUpdater(Zoznam z, TrackList tracks, CommDriver commDriver) {
        this.zoznam = z;
        this.tracks = tracks;
        this.commDriver = commDriver;
        parser = new MessageParser(z, commDriver);
       
    }
    
    public void stop() {
        running = false;
    }
    
    public void runThread() {
        if (thread != null)
            return;
        thread = new Thread(this);
        thread.start();
    }

    // DO NOT CALL DIRECTLY!
    // unfortunately Java does not allow to make this with protected access...
    @Override
    public void run() {
        running = true;
        
        while (running) {
            sleep();
            updateStatus();
            notifyListeners();
        }
    }
    
    private void sleep() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException ex) {
        }
        
    }
    
    private void updateStatus() {
        sendPendingSwitchRequests();
        updateClearance();
        updateSwitchStatuses();
        updateTrackBreakdown();
    }
    
    private void sendPendingSwitchRequests() {
        if (!commDriver.isConnected())
            return;
        List<Switch> pendingSwitches = new ArrayList<>();
        for (Switch sw : zoznam.dajZoznamVyhybiek()) {
            if (sw.hasStatusRequest()) {
                pendingSwitches.add(sw);
                sw.clearStatusRequest();
            }
        }
        
        if (pendingSwitches.isEmpty())
            return;
        CommData data = builder.buildSetSwitchStatusRequest(pendingSwitches);
        commDriver.send(data);
    }

    private void updateClearance() {
        if (!commDriver.isConnected())
            return;
        commDriver.send(builder.buildClearanceRequest(zoznam.getNodeIdList()));
        parser.parseClearanceStatusResponse();
    }
    
    private void updateSwitchStatuses() {
        if (commDriver.isConnected()) {
            commDriver.send(builder.buildGetSwitchStatusRequest(zoznam.getSwitchList()));
            parser.parseGetSwitchStatusResponse();
        }
        else {
            for (Switch sw : zoznam.dajZoznamVyhybiek()) {
                sw.prestav(sw.getRequestedStatus());
            }
        }
    }
    
    private void updateTrackBreakdown() {
        tracks.checkTrackBreakdowns();
       
    }
    
    public void addListener(TrackUpdateListener listener) {
        listeners.add(listener);
    }
    
    private void notifyListeners() {
        for (TrackUpdateListener listener : listeners) {
            listener.onUpdate();
        }
    }
}
